package com.exrobot.module.rbt.service.robotScheduler;

import com.exrobot.framework.common.enums.CommonStatusEnum;
import com.exrobot.framework.common.pojo.PageParam;
import com.exrobot.framework.common.util.collection.CollectionUtils;
import com.exrobot.module.rbt.controller.admin.order.vo.OrderSaveReqVO;
import com.exrobot.module.rbt.controller.admin.robotinfo.vo.RobotInfoPageReqVO;
import com.exrobot.module.rbt.controller.app.vo.MiniproMessageVO;
import com.exrobot.module.rbt.controller.app.vo.OrderDeliveryVO;
import com.exrobot.module.rbt.dal.dataobject.canteeninfo.CanteenInfoDO;
import com.exrobot.module.rbt.dal.dataobject.canteenmenu.CanteenMenuDO;
import com.exrobot.module.rbt.dal.dataobject.order.OrderDO;
import com.exrobot.module.rbt.dal.dataobject.orderitem.OrderItemDO;
import com.exrobot.module.rbt.dal.dataobject.robotbox.RobotBoxDO;
import com.exrobot.module.rbt.dal.dataobject.robotinfo.RobotInfoDO;
import com.exrobot.module.rbt.dal.redis.RbtRedisDAO;
import com.exrobot.module.rbt.enums.RbtTaskTypeEnum;
import com.exrobot.module.rbt.framework.util.CommonUtils;
import com.exrobot.module.rbt.service.canteeninfo.CanteenInfoService;
import com.exrobot.module.rbt.service.canteenmenu.CanteenMenuService;
import com.exrobot.module.rbt.service.mqtt.MqttMessageService;
import com.exrobot.module.rbt.service.order.OrderService;
import com.exrobot.module.rbt.service.orderitem.OrderItemService;
import com.exrobot.module.rbt.service.robotbox.RobotBoxService;
import com.exrobot.module.rbt.service.robotinfo.RobotInfoService;
import jakarta.annotation.Resource;
import jodd.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import software.amazon.awssdk.services.s3.endpoints.internal.Value;

import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
@Validated
public class RobotSchedulerServiceImpl implements RobotSchedulerService {

    @Resource
    private OrderService orderService;

    @Resource
    private OrderItemService orderItemService;

    @Resource
    private CanteenInfoService canteenInfoService;

    @Resource
    private CanteenMenuService canteenMenuService;

    @Resource
    private RobotBoxService robotBoxService;

    @Resource
    private RobotInfoService robotInfoService;

    @Resource
    private RbtRedisDAO redisDAO;

    @Resource
    private MqttMessageService mqttMessageService;

    /**
     * 调度满足条件的车辆
     * */
    @Override
    public RobotInfoDO orderMatchRobot(String canteenFloor, List<OrderItemDO> orderItems) {
        if (orderItems == null || orderItems.isEmpty()) {
            return null;
        }
        //0、获取订单楼层信息
        if (StringUtil.isBlank(canteenFloor)) {
            canteenFloor = canteenInfoService.getCanteenFloor(orderItems.get(0).getCanteenSn());
        }
        if (StringUtil.isBlank(canteenFloor)) { //找不到餐厅的位置没有办法了
            return null;
        }
        //1、根据订单判断需求机器人餐盒需求
        Map<Integer, Long> boxSizeNumMap = canteenMenuService.getBoxSizeNumMap(CollectionUtils.convertSet(orderItems, OrderItemDO::getMenuSn));
        if (boxSizeNumMap == null || boxSizeNumMap.isEmpty()) { //订单菜单找不到配置信息
            boxSizeNumMap.put(1,orderItems.stream().count());
        }
        //2、获取可用的机器人
        RobotInfoPageReqVO pageReqVO = new RobotInfoPageReqVO();
        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
        pageReqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
        List<RobotInfoDO> list = robotInfoService.getRobotInfoList(pageReqVO);
        if (list == null || list.isEmpty()) {
            log.info("没有机器人可用");
            return null;
        }
        //3、获取所有机器人对的配送柜子信息
        Map<String, List<RobotBoxDO>> robotBoxMap = robotBoxService.getRobotBoxMap(CollectionUtils.convertList(list, RobotInfoDO::getSn));
        if (robotBoxMap == null || robotBoxMap.isEmpty()) {
            return null;
        }
        //4、获取所有已经使用的配送柜子
        Map<String, List<Integer>> useRobotBoxMap = orderItemService.getRobotUseBox(robotBoxMap.keySet());

        //5、循环所有的车辆餐盒判断是否满足
        RobotInfoDO matchRobot = null;
        for (RobotInfoDO robotObj : list) {
            List<RobotBoxDO> boxDOList = robotBoxMap.containsKey(robotObj.getSn()) ? robotBoxMap.get(robotObj.getSn()) : robotBoxMap.get("0");
            if (boxDOList == null || boxDOList.isEmpty()) {
                continue;
            }
            List<Integer> allUseBoxList = new ArrayList<>();
            List<Integer> errList = redisDAO.getLockErr(robotObj.getSn());
            if (errList != null && !errList.isEmpty()) {
                allUseBoxList.addAll(errList);
            }
            if (useRobotBoxMap.containsKey(robotObj.getSn())) {
                allUseBoxList.addAll(useRobotBoxMap.get(robotObj.getSn()));
            }
            if (!allUseBoxList.isEmpty()) {
                boxDOList = boxDOList.stream().filter(w -> !allUseBoxList.contains(w.getBoxNo())).toList();
            }
            if (boxDOList.isEmpty()) { //完全被占用
                continue;
            }
            String robotFloor = robotInfoService.getRobotFloor(robotObj.getSn());
            boolean sameFloor = canteenFloor.equals(robotFloor);
            Map<Integer, Long> noUseBoxMap = boxDOList.stream().collect(Collectors.groupingBy(RobotBoxDO::getFoodSize,Collectors.counting()));
            if(canFulfillBox(boxSizeNumMap,noUseBoxMap)) {
                if(sameFloor) { //同层楼满足直接返回
                    return robotObj;
                }
                matchRobot = robotObj;
            }
        }
        return matchRobot;
    }

    public boolean canFulfillBox(Map<Integer, Long> needBoxSizeNumMap ,Map<Integer, Long> noUseBoxMap) {
        for(Map.Entry<Integer,Long> entry : needBoxSizeNumMap.entrySet()) {
            if(!noUseBoxMap.containsKey(entry.getKey())) {
                return false;
            }
            if(noUseBoxMap.get(entry.getKey()) < entry.getValue()) {
                return false;
            }
        }
        return true;
    }

    /**
     * 配餐完成时匹配
     * */
    @Override
    public OrderDO processCanteenOrder(String robotSn,List<OrderItemDO> orderItems) {
        //1、匹配车辆
//        RobotInfoDO matchRobot = orderMatchRobot(null,orderItems);
//        if(matchRobot == null) {// 没有匹配到等会在处理吧
//            return;
//        }
        //2、更新订单
        OrderDO orderDO = orderService.matchToDayOrderAndUpdate(robotSn,orderItems);
        if(orderDO == null) {
            return null;
        }

        //3、发送通知消息
        OrderDeliveryVO orderDeliveryVO = new OrderDeliveryVO();
        orderDeliveryVO.setOrderSn(orderDO.getOrderSn());
        orderDeliveryVO.setRobotNo(robotSn);
        orderDeliveryVO.setCode(orderDO.getCheckCode());
        mqttMessageService.sendOrderDelivery(Arrays.asList(orderDeliveryVO));

        MiniproMessageVO messageVO = new MiniproMessageVO();
        messageVO.setOrderSn(orderDO.getOrderSn());
        messageVO.setType(RbtTaskTypeEnum.DELIVERY.getTypeVal());
        messageVO.setContent("开始");
        mqttMessageService.sendMiniproMessage(messageVO);

        return orderDO;
    }

    public void processCanteenOrder1(List<OrderItemDO> orderItems) {

        if(orderItems == null || orderItems.isEmpty()) {
            return;
        }
        Long canteenSn = orderItems.get(0).getCanteenSn();
        CanteenInfoDO canteenInfoDO = canteenInfoService.getCanteenInfoBySn(canteenSn);
        if(canteenInfoDO == null || StringUtil.isBlank(canteenInfoDO.getAddress())) {
            return;
        }
        String canteenFloor = CommonUtils.getFloorByPoint(canteenInfoDO.getAddress());
        if(StringUtil.isBlank(canteenFloor)) {
            return;
        }
        Map<Long,Long> foodNumMap = orderItems.stream().collect(Collectors.groupingBy(OrderItemDO::getMenuSn,Collectors.counting()));
        Map<Long,CanteenMenuDO> menuMap = canteenMenuService.getCanteenMenuMapByMenuSn(foodNumMap.keySet());
        Long minSizeNum = 0L;
        Long maxSizeNum = 0L;
        for (Map.Entry<Long, Long> entry : foodNumMap.entrySet()) {
            if(menuMap.containsKey(entry.getKey())) {
                CanteenMenuDO menuDO = menuMap.get(entry.getKey());
                if(menuDO.getFoodSize().equals(1)) {
                    minSizeNum += entry.getValue();
                } else if(menuDO.getFoodSize().equals(2)){
                    maxSizeNum += entry.getValue();
                }
            }
        }
        String robotSn = getSafeRobot(canteenFloor,minSizeNum,maxSizeNum);
        if(StringUtil.isBlank(robotSn)) {
            return;
        }
        orderService.matchToDayOrderAndUpdate(robotSn,orderItems);
    }

    private String getSafeRobot(String canteenFloor,Long minSizeNum,Long maxSizeNum) {
        Map<String,String> robotFloorMap = robotInfoService.getAllRobotFloorMap();
        if(robotFloorMap == null || robotFloorMap.isEmpty()) {
            return null;
        }
        for(Map.Entry<String, String> entry : robotFloorMap.entrySet()) {
            if(entry.getValue().equals(canteenFloor)) {
                String robotSn = entry.getKey();
                if(checkSafeRobotBox(robotSn,minSizeNum,maxSizeNum)) {
                    return robotSn;
                }
            }
        }
        for(Map.Entry<String, String> entry : robotFloorMap.entrySet()) {
            String robotSn = entry.getKey();
            if(checkSafeRobotBox(robotSn,minSizeNum,maxSizeNum)) {
                return robotSn;
            }
        }
        return null;
    }

    private boolean checkSafeRobotBox(String robotSn, Long minSizeNum, Long maxSizeNum) {
        List<RobotBoxDO> noUseBoxList = robotBoxService.getNoUseRobotBoxByRobotSn(robotSn);
        if(noUseBoxList == null || noUseBoxList.isEmpty()) {
            return false;
        }
        Map<Integer,Long> map = noUseBoxList.stream().collect(Collectors.groupingBy(RobotBoxDO::getFoodSize,Collectors.counting()));
        if(minSizeNum > 0L){
            if(!map.containsKey(1) || map.get(1) < minSizeNum) {
                return false;
            }
        }
        if(maxSizeNum > 0L){
            if(!map.containsKey(2) || map.get(2) < minSizeNum) {
                return false;
            }
        }
        return true;
    }


    /**
     * 机器人订单匹配情况
     * */
    @Override
    public void processRobotOrder(OrderSaveReqVO reqVO) {
        String floor = CommonUtils.getFloorByPoint(reqVO.getPoint());
        Map<Long,Long> foodNumMap = reqVO.getItemDOList().stream().collect(Collectors.groupingBy(OrderItemDO::getMenuSn,Collectors.counting()));
        List<SaleOrderItem> items = foodNumMap.entrySet().stream()
                .map(entry -> new SaleOrderItem(entry.getKey(), entry.getValue().intValue())).toList();

        SaleOrder order = new SaleOrder(reqVO.getOrderSn(),reqVO.getCheckCode(),floor,items);
        List<RobotFood>  robotFoodList = orderService.getRobotSalseFoodByToday();
        // 第一优先级：本层一辆车满足
        RobotFood singleFloorVehicle = findSingleVehicleOnSameFloor(order,robotFoodList);
        if (singleFloorVehicle != null) {
//            singleFloorVehicle.processOrder(order);
            reqVO.getItemDOList().forEach(item->{
                item.setRobotSn(singleFloorVehicle.getSn());
            });
            orderService.updateOrderBindRobotbox(reqVO);
            return; //"订单 " + order.getId() + " 已分配给: " + singleFloorVehicle;
        }

        // 第二优先级：本层多辆车组合满足
        List<RobotFood> sameFloorCombination = findVehicleCombinationOnSameFloor(order,robotFoodList);
        if (sameFloorCombination != null && !sameFloorCombination.isEmpty()) {
            processCombinationOrder(sameFloorCombination, order);
            return; //"订单 " + order.getId() + " 已分配给本层多辆车: sameFloorCombination.stream().map(RobotFood::toString).collect(Collectors.joining(", "));
        }

        // 第三优先级：其他层一辆车满足
        RobotFood singleOtherFloorVehicle = findSingleVehicleOnOtherFloor(order,robotFoodList);
        if (singleOtherFloorVehicle != null) {
            singleOtherFloorVehicle.processOrder(order);
            return;// "订单 " + order.getId() + " 已分配给其他层车辆: " + singleOtherFloorVehicle;
        }

        // 第四优先级：多层多辆车组合满足
        List<RobotFood> multiFloorCombination = findMultiFloorVehicleCombination(order,robotFoodList);
        if (multiFloorCombination != null && !multiFloorCombination.isEmpty()) {
            processCombinationOrder(multiFloorCombination, order);
            return;// "订单 " + order.getId() + " 已分配给多层多辆车: multiFloorCombination.stream().map(RobotFood::toString).collect(Collectors.joining(", "));
        }

        return;// "订单 " + order.getId() + " 无法满足，没有合适的配送车辆";
    }

    // 第一优先级：查找本层可单独满足订单的车辆
    private RobotFood findSingleVehicleOnSameFloor(SaleOrder order,List<RobotFood> robotFoodList) {
        String userFloor = order.getUserFloor();
        for (RobotFood robotFood : robotFoodList) {
            if (robotFood.getFloor().equals(userFloor) && robotFood.canFulfillOrder(order)) {
                return robotFood;
            }
        }
        return null;
    }

    // 第二优先级：查找本层可组合满足订单的车辆
    private List<RobotFood> findVehicleCombinationOnSameFloor(SaleOrder order,List<RobotFood> robotFoodList) {
        String userFloor = order.getUserFloor();
        List<RobotFood> sameFloorVehicles = robotFoodList.stream()
                .filter(v -> v.getFloor() == userFloor)
                .collect(Collectors.toList());

        return findMinimalCombination(sameFloorVehicles, order);
    }

    // 第三优先级：查找其他层可单独满足订单的车辆
    private RobotFood findSingleVehicleOnOtherFloor(SaleOrder order,List<RobotFood> robotFoodList) {
        String userFloor = order.getUserFloor();
        for (RobotFood vehicle : robotFoodList) {
            if (vehicle.getFloor() != userFloor && vehicle.canFulfillOrder(order)) {
                return vehicle;
            }
        }
        return null;
    }

    // 第四优先级：查找多层可组合满足订单的车辆
    private List<RobotFood> findMultiFloorVehicleCombination(SaleOrder order,List<RobotFood> robotFoodList) {
        return findMinimalCombination(robotFoodList, order);
    }

    // 查找满足订单的最小车辆组合
    private List<RobotFood> findMinimalCombination(List<RobotFood> candidateVehicles, SaleOrder order) {
        // 创建订单物品需求的映射
        Map<Long, Integer> remainingNeeds = new HashMap<>();
        for (SaleOrderItem item : order.getItems()) {
            remainingNeeds.put(item.getFoodId(), item.getNum());
        }

        List<RobotFood> selectedVehicles = new ArrayList<>();

        // 贪心算法：优先选择能满足最多剩余需求的车辆
        while (!remainingNeeds.isEmpty()) {
            RobotFood bestVehicle = null;
            int bestScore = -1;
            Map<Long, Integer> bestContribution = null;

            // 找到能满足最多剩余需求的车辆
            for (RobotFood vehicle : candidateVehicles) {
                if (selectedVehicles.contains(vehicle)) continue;

                Map<Long, Integer> contribution = new HashMap<>();
                int score = 0;

                for (Map.Entry<Long, Integer> need : remainingNeeds.entrySet()) {
                    Long foodId = need.getKey();
                    int needed = need.getValue();
                    int available = vehicle.getFoodNum(foodId);

                    if (available > 0) {
                        int canContribute = Math.min(needed, available);
                        contribution.put(foodId, canContribute);
                        score += canContribute;
                    }
                }

                if (score > bestScore) {
                    bestScore = score;
                    bestVehicle = vehicle;
                    bestContribution = contribution;
                }
            }

            // 如果没有找到能贡献的车辆，说明无法满足
            if (bestVehicle == null || bestScore == 0) {
                return null;
            }

            // 添加选中的车辆并更新剩余需求
            selectedVehicles.add(bestVehicle);
            for (Map.Entry<Long, Integer> entry : bestContribution.entrySet()) {
                Long foodId = entry.getKey();
                int newRemaining = remainingNeeds.get(foodId) - entry.getValue();

                if (newRemaining <= 0) {
                    remainingNeeds.remove(foodId);
                } else {
                    remainingNeeds.put(foodId, newRemaining);
                }
            }
        }

        return selectedVehicles;
    }

    // 处理组合订单，从多辆车中扣减库存
    private void processCombinationOrder(List<RobotFood> vehicles, SaleOrder order) {
        // 创建订单物品需求的映射
        Map<Long, Integer> remainingNeeds = new HashMap<>();
        for (SaleOrderItem item : order.getItems()) {
            remainingNeeds.put(item.getFoodId(), item.getNum());
        }

        // 从每辆车中扣减所需物品
        for (RobotFood vehicle : vehicles) {
            Map<Long, Integer> toDeduct = new HashMap<>();
            for (Map.Entry<Long, Integer> need : remainingNeeds.entrySet()) {
                Long foodId = need.getKey();
                int needed = need.getValue();
                int available = vehicle.getFoodNum(foodId);

                if (available > 0 && needed > 0) {
                    int deduct = Math.min(needed, available);
                    toDeduct.put(foodId, deduct);
                }
            }

            // 扣减库存
            for (Map.Entry<Long, Integer> entry : toDeduct.entrySet()) {
                Long foodId = entry.getKey();
                int num = entry.getValue();
                vehicle.addItem(foodId, vehicle.getFoodNum(foodId) - num);

                // 更新剩余需求
                int newRemaining = remainingNeeds.get(foodId) - num;
                if (newRemaining <= 0) {
                    remainingNeeds.remove(foodId);
                } else {
                    remainingNeeds.put(foodId, newRemaining);
                }
            }

            if (remainingNeeds.isEmpty()) break;
        }
    }
}
